package com.event.cacheclear.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.event.cacheclear.service.IClearCacheService;
import com.event.common.constant.CommonConstant;
import com.event.common.constant.RedisKeyConstant;
import com.event.common.model.EventCacheKey;
import com.event.core.parse.CacheableParse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Slf4j
public class ClearCacheService implements IClearCacheService {

    private RedisTemplate redisTemplate;

    private CacheableParse cacheableParse;

    public ClearCacheService(RedisTemplate redisTemplate, CacheableParse cacheableParse) {
        this.redisTemplate = redisTemplate;
        this.cacheableParse = cacheableParse;
    }

    @Override
    public void clearCache(String cacheKey) {
        List<String> keys = scanKeys(redisTemplate, cacheKey, CommonConstant.EVENT_CACHELIST_QUEUESIZE);
        if(CollUtil.isEmpty(keys)){
            return;
        }
        redisTemplate.delete(keys);
        log.info("======> ClearCacheService : 删除缓存：{}", JSONObject.toJSONString(keys));
        // 缓存队列达到上限，则添加到队列
        if(keys.size() >= CommonConstant.EVENT_CACHELIST_QUEUESIZE){
            addClearCacheQueue(cacheKey);
        }
    }

    @Override
    public void addClearCacheQueue(String cacheKey) {
        redisTemplate.opsForList().leftPush(RedisKeyConstant.CLEAR_CACHE_KEY_LIST, cacheKey);
    }

    @Override
    public void popQueueClearCache(int batchSize) {
        for(int i = 0 ; i < batchSize; i++){
            Object cacheObject = redisTemplate.opsForList().rightPop(RedisKeyConstant.CLEAR_CACHE_KEY_LIST);
            if(ObjectUtil.isNull(cacheObject)){
                return;
            }
            clearCache(cacheObject.toString());
        }
    }

    @Override
    public boolean lock(String key, int expire, TimeUnit unit) {
        return  redisTemplate.opsForValue().setIfPresent(key, DateUtil.now(), expire,unit);
    }

    @Override
    public void register(EventCacheKey eventCacheKey) {
        cacheableParse.addCacheKey(eventCacheKey);
    }

    @Override
    public List<EventCacheKey> getAliasCacheKey(String namespaceAlias) {
        Map<String, List<EventCacheKey>> cacheKeys = cacheableParse.getCacheKeys();
        if(CollUtil.isEmpty(cacheKeys)){
            return new ArrayList<>(0);
        }
        List<EventCacheKey> resultList = cacheKeys.get(namespaceAlias);
        if(CollUtil.isEmpty(resultList)){
            return new ArrayList<>(0);
        }
        return resultList;
    }

    /**
     * 扫描key
     * @param redisTemplate
     * @param pattern
     * @param count
     * @return
     */
    private List<String> scanKeys(RedisTemplate<String, String> redisTemplate, String pattern, int count) {
        Cursor<byte[]> scanCursor = redisTemplate.getConnectionFactory().getConnection().scan(ScanOptions.scanOptions().match(pattern).count(count).build());
        if(ObjectUtil.isNull(scanCursor)){
            return new ArrayList<>();
        }
        List<String> resultList = new ArrayList<>();
        while (scanCursor.hasNext()) {
            byte[] keyBytes = scanCursor.next();
            String key = new String(keyBytes);
            resultList.add(key);
        }
        return resultList;
    }
}
